package com.xiaotu.spider.downloader;

import java.io.IOException;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CookieStore;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.config.SocketConfig;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.client.MyHttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.apache.http.protocol.HttpContext;

import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.downloader.HttpClientGenerator;
import us.codecraft.webmagic.proxy.Proxy;

/**
 * @类名 MyHttpClientGenerator
 * @日期 2017年3月21日
 * @作者 高海军
 * @功能
 */
public class MyHttpClientGenerator extends HttpClientGenerator
{
	private PoolingHttpClientConnectionManager connectionManager;
	
	public MyHttpClientGenerator()
	{
		Registry<ConnectionSocketFactory> reg = RegistryBuilder
				.<ConnectionSocketFactory> create()
				.register("http", PlainConnectionSocketFactory.INSTANCE)
				.register("https",
						SSLConnectionSocketFactory.getSocketFactory())
				.build();
		connectionManager = new PoolingHttpClientConnectionManager(reg);
		connectionManager.setDefaultMaxPerRoute(100);
	}
	
	/**
	 * 此方法为新增加的，目的是修改路由参数
	 * @param maxSize 最大值
	 */
	public void setDefaultMaxPerRoute(int maxSize)
	{
		connectionManager.setDefaultMaxPerRoute(maxSize);
	}
	
	@Override
	public CloseableHttpClient getClient(Site site, Proxy proxy)
	{
		
		CredentialsProvider credsProvider = null;
		HttpClientBuilder httpClientBuilder = MyHttpClientBuilder.create();
		
		if (proxy != null && StringUtils.isNotBlank(proxy.getUser())
				&& StringUtils.isNotBlank(proxy.getPassword()))
		{
			credsProvider = new BasicCredentialsProvider();
			credsProvider
					.setCredentials(
							new AuthScope(
									proxy.getHttpHost().getAddress()
											.getHostAddress(),
									proxy.getHttpHost().getPort()),
							new UsernamePasswordCredentials(proxy.getUser(),
									proxy.getPassword()));
			httpClientBuilder.setDefaultCredentialsProvider(credsProvider);
		}
		
		if (site != null && site.getHttpProxy() != null
				&& site.getUsernamePasswordCredentials() != null)
		{
			credsProvider = new BasicCredentialsProvider();
			credsProvider.setCredentials(new AuthScope(site.getHttpProxy()), // 可以访问的范围
					site.getUsernamePasswordCredentials());// 用户名和密码
			httpClientBuilder.setDefaultCredentialsProvider(credsProvider);
		}
		
		httpClientBuilder.setConnectionManager(connectionManager);
		if (site != null && site.getUserAgent() != null)
		{
			httpClientBuilder.setUserAgent(site.getUserAgent());
		}
		else
		{
			httpClientBuilder.setUserAgent("");
		}
		if (site == null || site.isUseGzip())
		{
			httpClientBuilder.addInterceptorFirst(new HttpRequestInterceptor()
			{
				
				public void process(final HttpRequest request,
						final HttpContext context)
						throws HttpException, IOException
				{
					if (!request.containsHeader("Accept-Encoding"))
					{
						request.addHeader("Accept-Encoding", "gzip");
					}
				}
			});
		}
		
		SocketConfig socketConfig = SocketConfig.custom()
				.setSoTimeout(site.getTimeOut()).setSoKeepAlive(true)
				.setTcpNoDelay(true).build();
		httpClientBuilder.setDefaultSocketConfig(socketConfig);
		connectionManager.setDefaultSocketConfig(socketConfig);
		if (site != null)
		{
			httpClientBuilder.setRetryHandler(
					new DefaultHttpRequestRetryHandler(site.getRetryTimes(),
							true));
		}
		generateCookie(httpClientBuilder, site);
		return httpClientBuilder.build();
		
	}
	
	private void generateCookie(HttpClientBuilder httpClientBuilder, Site site)
	{
		CookieStore cookieStore = new BasicCookieStore();
		for (Map.Entry<String, String> cookieEntry : site.getCookies()
				.entrySet())
		{
			BasicClientCookie cookie = new BasicClientCookie(
					cookieEntry.getKey(), cookieEntry.getValue());
			cookie.setDomain(site.getDomain());
			cookieStore.addCookie(cookie);
		}
		for (Map.Entry<String, Map<String, String>> domainEntry : site
				.getAllCookies().entrySet())
		{
			for (Map.Entry<String, String> cookieEntry : domainEntry.getValue()
					.entrySet())
			{
				BasicClientCookie cookie = new BasicClientCookie(
						cookieEntry.getKey(), cookieEntry.getValue());
				cookie.setDomain(domainEntry.getKey());
				cookieStore.addCookie(cookie);
			}
		}
		httpClientBuilder.setDefaultCookieStore(cookieStore);
	}
	
}
